package cn.ppool.test.utils;

import org.apache.commons.lang3.reflect.FieldUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MapBeanUtil {

    private static Pattern linePattern = Pattern.compile("_(\\w)");

    /**
     * @return Map<String, Object>
     * @author pan
     * @Description: 下划线转换成驼峰命名法
     * @Create Date: 2020-09-03
     */
    public static Map<String, Object> lineToHump(Map<String, Object> lineMap) {
        Map<String, Object> humpMap = new HashMap<String, Object>();
        for (String oldKey : lineMap.keySet()) {
            Matcher matcher = linePattern.matcher(oldKey.toLowerCase());
            StringBuffer sb = new StringBuffer();
            while (matcher.find()) {
                matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
            }
            StringBuffer covKey = matcher.appendTail(sb);
            humpMap.put(covKey.toString(), lineMap.get(oldKey));

        }
        return humpMap;
    }


    /**
     * map转bean
     *
     * @param map
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> List<T> transMap2Bean(List<Map> map, Class<T> clazz, boolean keyToCamelCase) throws Exception {
        List<T> list = new LinkedList<>();
        for (Map ss : map) {
            if (keyToCamelCase) {
                ss = lineToHump(ss);
            }
            T obj = transMap2Bean(ss, clazz);
            list.add(obj);
        }
        return list;
    }



    /**
     * Map转对象
     *
     * @param map
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T transMap2Bean(Map map, Class<T> clazz) throws Exception {
        List<Field> ss = FieldUtils.getAllFieldsList(clazz);
        T kk = clazz.newInstance();
        for (Field f : ss) {
            String key = f.getName();
            //默认字段
            if (key.equals("serialVersionUID")) continue;
            if (key.equals("class")) continue;
            //
            if (map.containsKey(key)) {
                if (map.get(key) == null) continue;
                PropertyDescriptor property = new PropertyDescriptor(key, clazz);
                Method setter = property.getWriteMethod();
                if (property.getPropertyType().isEnum()) {//enum
                    List<Field> assd = FieldUtils.getAllFieldsList(Class.forName(property.getPropertyType().getName()));
                    for (Field ff : assd) {
                        if (map.get(key).equals(ff.getName())) {
                            setter.invoke(kk, ff.get(ff.getName()));
                            break;
                        }
                    }
                } else {
                    switch (property.getPropertyType().getName()) {
                        case "java.lang.Integer":
                            setter.invoke(kk, Integer.valueOf(String.valueOf(map.get(key))));
                            break;
                        case "java.lang.Long":
                            setter.invoke(kk, Long.parseLong(String.valueOf(map.get(key))));
                            break;
                        case "java.lang.Double":
                            setter.invoke(kk, Double.valueOf(String.valueOf(map.get(key))));
                            break;
                        case "java.util.Date":
                            Date date = DateTimeUtil.StrToTime(map.get(key).toString());
                            setter.invoke(kk, date);
                            break;
                        default:
                            try {
                                setter.invoke(kk, map.get(key));
                            } catch (Exception ex) {
                                throw new Exception("transMap2Bean:" + key, ex);
                            }
                            break;
                    }
                }
            }
        }
        return kk;
    }


    /**
     * 字符串日期转换成date
     *
     * @param date
     * @return
     */
    public static Date StrToTime(String date) throws Exception {
        if (date.indexOf('.') > -1) {
            date = date.substring(0, date.indexOf('.'));
        }
        if (date.length() == "yyyy-MM-dd HH:mm:ss".length() && Integer.valueOf(date.substring(0, 2)) >= 19 && isDateTime(date, "yyyy-MM-dd HH:mm:ss")) {
            DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return format1.parse(date);
        } else if (date.length() == "yyyyMMddHHmmss".length() && Integer.valueOf(date.substring(0, 2)) >= 19 && isDateTime(date, "yyyyMMddHHmmss")) {
            DateFormat format1 = new SimpleDateFormat("yyyyMMddHHmmss");
            return format1.parse(date);
        } else if (date.length() == "yyyy-MM-dd".length() && Integer.valueOf(date.substring(0, 2)) >= 19 && isDateTime(date, "yyyy-MM-dd")) { //YYYY-MM-DD
            DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd");
            return format1.parse(date);
        } else if (date.length() == "yyyyMMdd".length() && Integer.valueOf(date.substring(0, 2)) >= 19 && isDateTime(date, "yyyyMMdd")) { //YYYY-MM-DD
            DateFormat format1 = new SimpleDateFormat("yyyyMMdd");
            return format1.parse(date);
        } else if (SuperUtil.isInt(date)) {//时间戳单位是秒，不是毫秒
            return new Date(Long.parseLong(date) * 1000);
        }
        throw new Exception("不支持的时间：" + date);
    }

    /**
     * 判断是否正确日期
     *
     * @param str
     * @param fomat
     * @return
     */
    public static boolean isDateTime(String str, String fomat) {
        SimpleDateFormat format = new SimpleDateFormat(fomat); // 指定日期格式为四位年/两位月份/两位日期，注意yyyy-MM-dd HH:mm:ss区分大小写；
        try {// 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
            format.setLenient(false);
            format.parse(str);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

}
